﻿using FreeSql;
using Mapster;
using Mapster.Models;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Newtonsoft.Json;
using RunUI.AspNetCore;
using RunUI.Attributes;
using System.Linq.Expressions;

namespace RunUI
{
    public abstract class BaseCrudController<T> : BaseController where T : class, IBaseEntity
    {
        protected ITenantProvider TenantProvider { get; private set; } = null;
        protected string TenantId { get; private set; } = null;
        protected IFreeSql Orm { get; private set; } = null;
        protected IBaseRepository<T> Repository { get; set; } = null;

        protected IForeignEnumProvider ForeignEnumProvider { get; set; }
        protected IForeignRelationProvider ForeignRelationProvider { get; set; }

        protected IModelValidationProvider ModelValidationProvider { get; set; }

        protected Type CurrentModelType { get; private set; }

        protected object CurrentDtoModel { get; set; }
        protected Type CurrentDtoModelType { get; set; }
        protected T CurrentModel { get; set; }
        protected string BodyString { get; set; }


        public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
        {
            Orm = this.GetService<IFreeSql>();
            TenantProvider = this.GetService<ITenantProvider>();
            if (TenantProvider != null)
            {
                TenantId = await TenantProvider.GetTenantId();
            }

            Repository = GetRepository<T>();
            ForeignEnumProvider = this.GetService<IForeignEnumProvider>();
            ForeignRelationProvider = this.GetService<IForeignRelationProvider>();
            ModelValidationProvider = this.GetService<IModelValidationProvider>();

            CurrentModelType = typeof(T);

            if (context.HttpContext.Request.Method.EqualsIgnoreCase("POST"))
            {

                BodyString = await this.Request.Body.ReadToEndAsync(true);
                var CurrentDtoModelType = CurrentModelType;
                if (context.ActionDescriptor.DisplayName.EqualsIgnoreCase("Add"))
                {
                    var attr = CurrentModelType.GetTypeAttributes<DtoMapperAttribute>().Where(i => i.Type == AppEnum.DtoType.Add).FirstOrDefault();
                    if (attr == null)
                    {
                        attr = CurrentModelType.GetTypeAttributes<DtoMapperAttribute>().Where(i => i.Type == AppEnum.DtoType.Edit).FirstOrDefault();
                    }
                    if (attr != null)
                    {
                        CurrentDtoModelType = attr.DtoType;
                    }
                    try
                    {
                        CurrentDtoModel = JsonConvert.DeserializeObject(BodyString, CurrentDtoModelType);
                        var modelState = await ModelValidationProvider.Valid(CurrentDtoModel, CurrentDtoModelType);
                        if (!modelState.IsValid)
                        {
                            throw new RunUIModelStateDictionaryException(modelState);
                        }
                    }
                    catch (Exception ex)
                    {
                        CurrLogger.Debug(ex, $"[body]{BodyString} 不能转换为 {CurrentDtoModelType.FullName}");
                    }
                }
                else if (context.ActionDescriptor.DisplayName.EqualsIgnoreCase("Edit"))
                {

                    var attr = CurrentModelType.GetTypeAttributes<DtoMapperAttribute>().Where(i => i.Type == AppEnum.DtoType.Edit).FirstOrDefault();

                    if (attr != null)
                    {
                        CurrentDtoModelType = attr.DtoType;
                    }
                    try
                    {
                        CurrentDtoModel = JsonConvert.DeserializeObject(BodyString, CurrentDtoModelType);
                        var modelState = await ModelValidationProvider.Valid(CurrentDtoModel, CurrentDtoModelType);
                        if (!modelState.IsValid)
                        {
                            throw new RunUIModelStateDictionaryException(modelState);
                        }
                    }
                    catch (Exception ex)
                    {
                        CurrLogger.Debug(ex, $"[body]{BodyString} 不能转换为 {CurrentDtoModelType.FullName}");
                    }
                }

            }


            await base.OnActionExecutionAsync(context, next);
        }

        protected virtual IBaseRepository<K> GetRepository<K>() where K : class, IBaseEntity
        {
            var expression = ExpressionHelper.GetExpression<K>(TenantId);
            return Orm.GetRepository(expression);
        }

        protected virtual QueryHelper<T> GetQueryExpression()
        {
            return new QueryHelper<T>(BodyString);
        }
        protected virtual async Task<K> GetRequestBody<K>()
        {
            var body = await this.Request.Body.ReadToEndAsync();
            return body.JsonDeserialize<K>();
        }


        //[HttpPost]
        //public virtual async Task<object> List()
        //{
        //    var qg = new QueryHelper<T>(Request.Body);
        //    var type = CurrentModelType;
        //    var properties = type.GetProperties();
        //    //var propertyString = properties.Select(i => i.Name).Join(",");

        //    //var listDtoAttr = CurrentModelType.GetTypeAttributes<DtoMapperAttribute>().Where(i => i.Type == AppEnum.DtoType.List).FirstOrDefault();
        //    //if (listDtoAttr != null && listDtoAttr.DtoType != CurrentModelType)
        //    //{
        //    //    var listDtoModelProperties = listDtoAttr.DtoType.GetProperties();
        //    //    propertyString = listDtoModelProperties.Select(i => i.Name).Join(",");
        //    //}

        //    //var config = TypeAdapterConfig.GlobalSettings;
        //    //var key = new TypeTuple(CurrentModelType, listDtoAttr.DtoType);
        //    //var exp = config!.CreateMapExpression(key, MapType.Projection);


        //    //var method = typeof(FreeSqlRepositoryExtensions).GetMethod("ToDynamicPagedListAsync");

        //    //dynamic pagedList = method.Invoke(null, new object[] { Repository, qg, Expression.Quote(exp), ExpressionHelper.GetExpression<T, DateTime>(i => i.UpdateTime), true });

        //    #region  填充属性中的Select
        //    //var select = new List<LabelValueGroup>();
        //    //{
        //    //    foreach (var property in properties)
        //    //    {
        //    //        if (property.PropertyType.IsEnum || property.PropertyType.IsEnumNullable())
        //    //        {
        //    //            var enumType = property.PropertyType.IsEnum ? property.PropertyType : property.PropertyType.GetGenericArguments()[0];
        //    //            var maps = enumType.GetEnumMap();
        //    //            select.Add(new LabelValueGroup
        //    //            {
        //    //                Children = maps,
        //    //                Name = property.Name,
        //    //                SelectType = AppEnum.SelectType.列表,
        //    //            });
        //    //        }
        //    //        else if (property.IsPropertyHasAttribute<ForeignEnumAttribute>(out var attr))
        //    //        {
        //    //            var treeNodes = await ForeignEnumProvider.GetEnumValuesAsync(attr.EnumCode);
        //    //            select.Add(new LabelValueGroup
        //    //            {
        //    //                Children = treeNodes,
        //    //                Name = property.Name,
        //    //                SelectType = AppEnum.SelectType.树
        //    //            });
        //    //        }
        //    //        else if (property.IsPropertyHasAttribute<ForeignRelationAttribute>(out var attr1))
        //    //        {
        //    //            var values = pagedList.Rows.Select(i => property.GetValue(i, null).ToStringExt()).ToList();
        //    //            var maps = await ForeignRelationProvider.GetForeignRelationsAsync(attr1, values.ToArray());
        //    //            select.Add(new LabelValueGroup
        //    //            {
        //    //                Children = maps,
        //    //                Name = property.Name,
        //    //                SelectType = AppEnum.SelectType.列表
        //    //            });
        //    //        }
        //    //    }
        //    //}
        //    #endregion


        //    return new PagedListResult<T> { List = pagedList };
        //}

        [HttpGet]
        public virtual async Task<T> Get([FromQuery] string id)
        {
            var model = await Repository.Where(i => i.Id == id).FirstAsync();
            if (model == null)
            {
                throw new RunUIServiceMessageException("当前编号不正确");
            }

            var p = CurrentModelType.GetProperties().FirstOrDefault(i => i.IsPropertyHasAttribute<PasswordAttribute>());
            if (p != null)
            {
                p.SetValue(model, "");
            }


            return model;
        }


        [HttpPost]
        public virtual async Task<string> Add([FromQuery] string id)
        {
            CurrentModel = CurrentDtoModel.Adapt<T>();
            CurrentModel.Id = OrderIdHelper.NewId();
            CurrentModel.OperateUserId = UserId;
            await Repository.InsertAsync(CurrentModel);

            return CurrentModel.Id;
        }

        [HttpPost]
        public virtual async Task Edit([FromQuery] string id)
        {
            var model = await Repository.Where(i => i.Id == id).FirstAsync();
            if (model == null)
            {
                throw new RunUIServiceMessageException("当前编号不正确");
            }

            CurrentDtoModel.Adapt(model);
            model.OperateUserId = UserId;
            await Repository.UpdateAsync(model);
        }


        [HttpPost]
        public virtual async Task Delete()
        {
            var qg = new QueryHelper<T>(BodyString);
            var where = qg.GetExpression();
            await Orm.Update<T>().Where(where).Set(i => i.Flag, -1).ExecuteAffrowsAsync();
        }

    }
}
